Skip to content

chore: remove some infrastructure tests (moved to dedicated repository) #596

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Dec 5, 2024

Conversation

gfyrag
Copy link
Contributor

@gfyrag gfyrag commented Nov 29, 2024

No description provided.

@gfyrag gfyrag requested a review from a team as a code owner November 29, 2024 15:55
Copy link

coderabbitai bot commented Nov 29, 2024

Warning

Rate limit exceeded

@gfyrag has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 15 minutes and 30 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 1ed7c23 and bdf9a16.

Walkthrough

The pull request introduces significant changes to the build, deployment, and testing configurations across multiple Earthfiles and Go files. Key updates include the addition of new build steps, enhancements to testing arguments, and restructuring of deployment logic using Pulumi. Several files have been removed, indicating a shift in strategy, particularly in the Helm and rolling upgrades areas. New components and functions have been added to support improved integration and functionality, reflecting a comprehensive update to the project's infrastructure.

Changes

File Path Change Summary
Earthfile Added new build step for deployments, updated OpenAPI section with yq, modified generate-client with jq, and refined testing arguments and coverage logic.
deployments/pulumi/Earthfile Enhanced build configuration with caching, added new sections for tidy, lint, and pre-commit.
deployments/pulumi/main.go Changed main function to call pulumi.Run(deploy), renamed deployLedger to deploy, and updated deployment logic to use pulumi_ledger.
test/rolling-upgrades/Earthfile Entire file removed, indicating a change in build and testing strategy.
test/rolling-upgrades/main_test.go Entire file removed, which contained tests for rolling upgrades.
pkg/generate/set.go Modified Run method to handle untilLogID condition and enhanced error handling.
tools/generator/pulumi/Earthfile New Earthfile created for the ledger project, defining build and caching processes.
tools/generator/pulumi/main.go New file implementing a Pulumi application for generating ledger components.
tools/generator/pulumi/pkg/component.go Introduced GeneratorComponent and GeneratorComponentArgs types for managing Pulumi resources.
deployments/helm/.helmignore File deleted, removing ignore patterns for Helm package builds.
deployments/helm/Earthfile File deleted, which defined build configuration for Helm.
deployments/helm/README.md File deleted, which provided usage warnings for the Helm chart.
deployments/helm/templates/NOTES.txt File deleted, which contained instructions for accessing the application after deployment.
deployments/helm/templates/_helpers.tpl File deleted, which included template definitions for Helm chart.
deployments/pulumi/main_test.go New file added to test PostgreSQL deployment using Pulumi and Helm.
deployments/pulumi/pkg/component.go New file added for managing Kubernetes deployment of the ledger service.
test/rolling-upgrades/README.md File deleted, which contained documentation for rolling upgrade tests.

Poem

In the burrows deep, where the code does hop,
New builds and tests, we’ll never stop!
With every tweak, our projects grow,
Hopping through changes, to and fro.
A sprinkle of yq, a dash of jq,
In the land of code, we’ll always break through! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🧹 Outside diff range and nitpick comments (32)
deployments/pulumi/postgres/main.go (2)

13-17: Consider improving configuration handling.

While the current implementation works, consider these improvements:

  1. Use a specific config name instead of an empty string in config.New()
  2. Consider making the default namespace configurable or documented
-		conf := config.New(ctx, "")
+		conf := config.New(ctx, "postgres")

1-27: Consider documenting integration points and deployment requirements.

As this is part of a larger restructuring effort ("pulumi split"), it would be valuable to:

  1. Document the prerequisites and deployment requirements
  2. Clarify how this PostgreSQL component fits into the broader architecture
  3. Consider adding comments explaining the expected configuration values
test/rolling-upgrades/generator/main.go (3)

19-19: Consider making the default image configurable

The default image URL is hardcoded. Consider moving this to a constant or environment variable for easier maintenance and flexibility across environments.

+const defaultGeneratorImage = "ghcr.io/formancehq/ledger-generator:latest"
+
 func main() {
     // ...
     if image == "" {
-        image = "ghcr.io/formancehq/ledger-generator:latest"
+        image = defaultGeneratorImage
     }

23-30: Enhance error handling and consider component lifecycle

While basic error handling is present, consider:

  1. Adding more context to the error return
  2. Explicitly handling component cleanup if needed
 _, err = pulumi_generator.NewGeneratorComponent(ctx, "generator", &pulumi_generator.GeneratorComponentArgs{
     Namespace: pulumi.String(namespace),
     LedgerURL: pulumi.String(ledgerURL),
     Image:     pulumi.String(image),
 })
 if err != nil {
-    return err
+    return fmt.Errorf("failed to create generator component: %w", err)
 }

1-8: Add package documentation

Consider adding a package comment explaining:

  • The purpose of this generator
  • Required configuration values
  • Usage examples
 package main

+// Package main provides a Pulumi program for deploying and managing the ledger generator.
+//
+// Configuration:
+// - namespace: (optional) Kubernetes namespace, defaults to "default"
+// - image: (optional) Generator image, defaults to ghcr.io/formancehq/ledger-generator:latest
+// - ledger-url: (required) URL of the ledger service
+
 import (
deployments/pulumi/ledger/Earthfile (1)

28-38: Consider adjusting linting configuration

Two potential improvements for the lint target:

  1. The --fix flag automatically modifies code, which might not be ideal in CI pipelines. Consider running without --fix in CI and only using it locally.
  2. The 5-minute timeout might be insufficient for larger codebases. Consider increasing it or making it configurable.
-    RUN golangci-lint run --fix --build-tags it --timeout 5m
+    ARG LINT_TIMEOUT="5m"
+    ARG CI="false"
+    IF [ "$CI" = "true" ]
+        RUN golangci-lint run --build-tags it --timeout=$LINT_TIMEOUT
+    ELSE
+        RUN golangci-lint run --fix --build-tags it --timeout=$LINT_TIMEOUT
+    END
deployments/pulumi/postgres/Earthfile (2)

12-17: Enhance file copying robustness

While the basic file copying is in place, consider adding:

  1. Validation for required files before proceeding
  2. More specific error messages if critical files are missing
  3. Consider using --if-exists flag for optional files
 sources:
     FROM core+builder-image
     WORKDIR /src
-    COPY *.go go.* Pulumi.yaml .
+    COPY main.go go.* Pulumi.yaml .
+    COPY --if-exists *.go .
     COPY --dir pkg .
+    RUN test -f main.go && test -f go.mod && test -f Pulumi.yaml
     SAVE ARTIFACT /src

39-41: Consider adding more pre-commit checks

The pre-commit stage could be enhanced with additional checks:

  1. Unit tests
  2. Security scanning
  3. Dependency vulnerability checks
 pre-commit:
     BUILD +tidy
     BUILD +lint
+    BUILD +test
+    BUILD +security-scan
test/rolling-upgrades/generator/Earthfile (2)

12-22: Consider more specific source copying strategy.

The current source copying strategy (COPY ../../..+sources/src /src) is quite broad. Consider being more specific about which files are needed to reduce build context size and improve build performance.

-    COPY ../../..+sources/src /src
+    COPY ../../..+sources/src/test/rolling-upgrades/generator /src/test/rolling-upgrades/generator
+    COPY ../../..+sources/src/go.mod /src/
+    COPY ../../..+sources/src/go.sum /src/

43-45: Consider adding more pre-commit checks.

The pre-commit target could benefit from additional checks such as:

  • Unit tests
  • Security scanning
  • Generated code verification
 pre-commit:
     BUILD +tidy
     BUILD +lint
+    BUILD +test
+    BUILD +security-scan
+    BUILD +verify-generated
deployments/pulumi/ledger/main.go (2)

11-14: Consider adding explicit error handling for the required PostgreSQL URI.

While Require() will panic if the value is missing, consider using RequireSecret() if the URI contains sensitive information, or implement explicit error handling for better operational control.

-		postgresURI := conf.Require("postgres.uri")
+		postgresURI, err := conf.TrySecret("postgres.uri")
+		if err != nil {
+			return fmt.Errorf("postgres URI is required: %w", err)
+		}

41-51: Add context to component initialization error.

While the error is captured, adding context would help with debugging deployment issues.

-		_, err = pulumi_ledger.NewLedgerComponent(ctx, "ledger", &pulumi_ledger.LedgerComponentArgs{
+		_, err = pulumi_ledger.NewLedgerComponent(ctx, "ledger", &pulumi_ledger.LedgerComponentArgs{
			// ... existing args ...
		})
+		if err != nil {
+			return fmt.Errorf("failed to create ledger component: %w", err)
+		}
test/rolling-upgrades/Earthfile (3)

59-65: Document the CLUSTER_NAME parameter

The requirements target consolidates multiple build steps effectively. However, consider adding a comment to document the purpose and format of the CLUSTER_NAME parameter, as it's used across multiple targets.

+# CLUSTER_NAME: Unique identifier for the test cluster (default: test-rolling-upgrades)
+# Used across multiple targets for consistent resource naming
 requirements:
     ARG CLUSTER_NAME=test-rolling-upgrades

103-106: Consider parameterizing image references

The test command uses hardcoded image references with the cluster name. Consider extracting these as arguments for better reusability and maintainability.

+ARG TEST_IMAGE_REPO=ghcr.io/formancehq/ledger-generator
 go test \
-    --test-image ghcr.io/formancehq/ledger-generator:$CLUSTER_NAME-rolling-upgrade-test \
+    --test-image $TEST_IMAGE_REPO:$CLUSTER_NAME-rolling-upgrade-test \
     --latest-version $CLUSTER_NAME-main \
     --actual-version $CLUSTER_NAME-current \
     --stack $CLUSTER_NAME-rolling-upgrade-test \

Line range hint 1-130: Document the rolling upgrade test strategy

Consider adding a README.md in the test/rolling-upgrades directory to document:

  • The purpose and strategy of rolling upgrade tests
  • The relationship between Pulumi configurations and these tests
  • The test infrastructure setup and requirements
  • Common troubleshooting steps

This documentation would be valuable for maintaining and extending the test infrastructure as the Pulumi split evolves.

deployments/pulumi/postgres/pkg/component.go (8)

9-13: Add GoDoc comment to the exported type PostgresComponent

The exported type PostgresComponent should have a documentation comment to improve code readability and maintainability.


15-17: Add GoDoc comment to the exported type PostgresComponentArgs

The exported type PostgresComponentArgs should have a documentation comment to improve code readability and maintainability.


19-19: Add GoDoc comment to the exported function NewPostgresComponent

The exported function NewPostgresComponent should have a documentation comment to improve code readability and maintainability.


23-24: Wrap error with context when returning

To provide more context for debugging, wrap the error with additional information.

-return nil, err
+return nil, fmt.Errorf("registering component resource: %w", err)

31-31: Use unique release names to prevent conflicts

Using a hardcoded release name "postgres" may lead to conflicts if multiple instances are deployed. Consider incorporating the name parameter into the release name for uniqueness.

-rel, err := helm.NewRelease(ctx, "postgres", &helm.ReleaseArgs{
+rel, err := helm.NewRelease(ctx, name, &helm.ReleaseArgs{

38-38: Make database name configurable

Hardcoding the database name as "ledger" reduces flexibility. Consider allowing the database name to be specified via component arguments.


43-44: Consider making resource requests configurable

Hardcoding resource requests for CPU and memory reduces flexibility. Allow these values to be specified via component arguments to adapt to different deployment environments.


49-49: Avoid creating the default namespace unnecessarily

Creating the "default" namespace is unnecessary and may cause errors. Set CreateNamespace to false when deploying to the default namespace.

You can modify the code as follows:

+	createNamespace := pulumi.Bool(true)
+	if namespace == pulumi.String("default") {
+		createNamespace = pulumi.Bool(false)
+	}
...
-		CreateNamespace: pulumi.BoolPtr(true),
+		CreateNamespace: createNamespace,
deployments/pulumi/ledger/pkg/component.go (4)

9-16: Add GoDoc comments to exported type LedgerComponent

To improve code readability and documentation, consider adding GoDoc comments to the exported type LedgerComponent.


18-27: Add GoDoc comments to exported type LedgerComponentArgs

To enhance code maintainability and provide clear documentation, please add GoDoc comments to the exported type LedgerComponentArgs.


29-29: Add GoDoc comment to exported function NewLedgerComponent

Adding a GoDoc comment to the function NewLedgerComponent will help other developers understand its purpose and usage.


61-61: Consider retrieving the service port dynamically instead of hardcoding

Currently, the service port is hardcoded to 8080. If the service port changes in the Helm chart, this value may become outdated. Consider retrieving the service port dynamically to ensure consistency.

test/rolling-upgrades/generator/pkg/component.go (3)

46-46: Make the parallelism parameter configurable

The hardcoded value "30" for the -p (parallelism) parameter may limit flexibility. Consider making it configurable to accommodate different use cases.

Apply the following changes:

  1. Update the GeneratorComponentArgs struct to include a new field:
 type GeneratorComponentArgs struct {
 	Namespace pulumi.StringInput
 	LedgerURL pulumi.StringInput
 	Image     pulumi.StringInput
+	Parallelism pulumi.StringInput
 }
  1. Modify the generatorArgs assignment to use the new Parallelism parameter:
 generatorArgs := pulumi.StringArray{
 	args.LedgerURL,
 	pulumi.String("/examples/example1.js"),
 	pulumi.String("-p"),
-	pulumi.String("30"),
+	args.Parallelism,
 }
  1. Ensure that when creating a new GeneratorComponent, you provide the Parallelism argument as needed.

67-67: Rename the container for clarity

The container is currently named "test". For better clarity, consider renaming it to "generator" to reflect its purpose.

Apply the following change:

 Name: pulumi.String("test"),
+// Rename "test" to "generator" for clarity
-Name: pulumi.String("test"),
+Name: pulumi.String("generator"),

75-79: Review the custom timeout settings

The timeouts for Create, Update, and Delete operations are all set to "10s". Depending on the environment, pod creation and deletion might take longer. Consider increasing these timeouts to avoid potential issues during resource operations.

For example, you could adjust the timeouts as follows:

 pulumi.Timeouts(&pulumi.CustomTimeouts{
-	Create: "10s",
-	Update: "10s",
-	Delete: "10s",
+	Create: "2m",
+	Update: "2m",
+	Delete: "2m",
 }),
test/rolling-upgrades/main_test.go (2)

203-213: Make the Helm chart path configurable

In the resource transform, the Helm chart path is hardcoded to "../../deployments/helm". For better flexibility and maintainability, consider making the chart path configurable.

Apply this diff to use a configuration value:

+ chartPath := config.Require(ctx, "ledger:chartPath")
pulumi.Transforms([]pulumi.ResourceTransform{
    // Update relative location of the helm chart
    func(context context.Context, args *pulumi.ResourceTransformArgs) *pulumi.ResourceTransformResult {
        if args.Type == "kubernetes:helm.sh/v3:Release" {
-           args.Props["chart"] = pulumi.String("../../deployments/helm")
+           args.Props["chart"] = pulumi.String(chartPath)
        }
        return &pulumi.ResourceTransformResult{
            Props: args.Props,
        }
    },
}),

Ensure to set the ledger:chartPath configuration before running the stack.


Line range hint 131-139: Use logging instead of printing directly to stdout/stderr

Currently, the function upAndPrintOutputs prints StdOut and StdErr directly using fmt.Println. Consider using the logging framework to output these messages to ensure they are captured appropriately in test logs.

Apply this diff:

if out.StdErr != "" {
-   fmt.Println(out.StdErr)
+   logging.FromContext(ctx).Error(out.StdErr)
}
...
if out.StdOut != "" {
-   fmt.Println(out.StdOut)
+   logging.FromContext(ctx).Info(out.StdOut)
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 90cb10b and f0c054e.

⛔ Files ignored due to path filters (11)
  • deployments/pulumi/ledger/Pulumi.yaml is excluded by !**/*.yaml
  • deployments/pulumi/ledger/go.mod is excluded by !**/*.mod
  • deployments/pulumi/ledger/go.sum is excluded by !**/*.sum, !**/*.sum
  • deployments/pulumi/postgres/Pulumi.yaml is excluded by !**/*.yaml
  • deployments/pulumi/postgres/go.mod is excluded by !**/*.mod
  • deployments/pulumi/postgres/go.sum is excluded by !**/*.sum, !**/*.sum
  • test/rolling-upgrades/generator/Pulumi.yaml is excluded by !**/*.yaml
  • test/rolling-upgrades/generator/go.mod is excluded by !**/*.mod
  • test/rolling-upgrades/generator/go.sum is excluded by !**/*.sum, !**/*.sum
  • test/rolling-upgrades/go.mod is excluded by !**/*.mod
  • test/rolling-upgrades/go.sum is excluded by !**/*.sum, !**/*.sum
📒 Files selected for processing (14)
  • Earthfile (1 hunks)
  • deployments/pulumi/Earthfile (0 hunks)
  • deployments/pulumi/ledger/Earthfile (1 hunks)
  • deployments/pulumi/ledger/main.go (1 hunks)
  • deployments/pulumi/ledger/pkg/component.go (1 hunks)
  • deployments/pulumi/main.go (0 hunks)
  • deployments/pulumi/postgres/Earthfile (1 hunks)
  • deployments/pulumi/postgres/main.go (1 hunks)
  • deployments/pulumi/postgres/pkg/component.go (1 hunks)
  • test/rolling-upgrades/Earthfile (7 hunks)
  • test/rolling-upgrades/generator/Earthfile (1 hunks)
  • test/rolling-upgrades/generator/main.go (1 hunks)
  • test/rolling-upgrades/generator/pkg/component.go (1 hunks)
  • test/rolling-upgrades/main_test.go (4 hunks)
💤 Files with no reviewable changes (2)
  • deployments/pulumi/Earthfile
  • deployments/pulumi/main.go
🔇 Additional comments (21)
deployments/pulumi/postgres/main.go (4)

1-8: LGTM! Clean package structure and imports.

The package declaration and imports are well-organized and include all necessary dependencies.


10-11: LGTM! Follows Pulumi best practices.

The main function structure correctly implements Pulumi's programming model with proper error handling.


25-27: LGTM! Proper error handling and return.

The function correctly propagates errors and returns nil on success.


18-23: Verify PostgreSQL component dependencies and configuration.

The component creation looks good, but let's verify the dependencies and configuration options.

✅ Verification successful

PostgreSQL component implementation is complete and properly configured

The component implementation is well-structured with:

  • Proper namespace handling with a default value
  • Complete Helm chart configuration including:
    • Database credentials and name
    • Resource requests for memory and CPU
    • Service name generation
  • Appropriate error handling and resource registration
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for PostgreSQL component definition and configuration options

# Check for the component definition
ast-grep --pattern 'type PostgresComponentArgs struct {
  $$$
}'

# Look for other usages of the component
rg -l "NewPostgresComponent" --type go

Length of output: 433


Script:

#!/bin/bash
# Check the component implementation and its configuration
ast-grep --pattern 'func NewPostgresComponent($$$) {
  $$$
}'

# Check test usage for configuration patterns
rg "NewPostgresComponent" -A 5 -B 2 test/rolling-upgrades/main_test.go

Length of output: 296


Script:

#!/bin/bash
# Check the actual component implementation for required configurations
cat deployments/pulumi/postgres/pkg/component.go

Length of output: 1782

test/rolling-upgrades/generator/main.go (1)

4-4: ⚠️ Potential issue

Package name mismatch with usage

The imported package github.com/formancehq/ledger/test/rolling-upgrades/generator/pkg is used as pulumi_generator in the code. This suggests a potential package name mismatch.

Either:

  1. Update the import alias to match the package name, or
  2. Ensure the package declaration in pkg/component.go matches the usage
✅ Verification successful

Import usage is correct, no changes needed

The package name in pkg/component.go is correctly declared as package pulumi_generator, which matches its usage in the code. The import path and package name can be different in Go, and this is a common practice.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the package name in the generator/pkg directory
cat test/rolling-upgrades/generator/pkg/component.go | grep "package"

Length of output: 94

deployments/pulumi/ledger/Earthfile (4)

6-11: Well-structured caching configuration

The caching strategy is well-implemented with shared caches for Go modules, build cache, and linting cache, which will significantly improve build performance.


19-27: LGTM! Well-structured dependency management

The tidy target correctly manages Go dependencies and saves the necessary artifacts.


1-5: Consider upgrading Earthly version

The Earthfile uses VERSION 0.8, which is relatively old. Consider upgrading to a newer version to benefit from the latest features and improvements.

✅ Verification successful

Version 0.8 is the current standard across the project

The Earthfile's VERSION 0.8 aligns with the project-wide standard, as all other Earthfiles in the repository also use VERSION 0.8. The latest Earthly release (v0.8.15) is also in the 0.8.x series, confirming that this version is current and appropriate.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check latest Earthly version from their releases
curl -s https://api.github.com/repos/earthly/earthly/releases/latest | jq -r '.tag_name'

Length of output: 96


Script:

#!/bin/bash
# Let's check if there are any other Earthfiles in the repository to understand the version usage pattern
fd Earthfile --type f --exec head -n 1 {}

Length of output: 177


12-18: Verify completeness of source files

The sources target might be missing some important files:

  1. Pulumi stack configuration files (Pulumi.*.yaml)
  2. Other potential configuration files needed for the deployment
✅ Verification successful

Let me check if there are any stack-specific configuration files that might be needed.


Source files are correctly configured

The current setup is appropriate for this Pulumi project:

  • Pulumi.yaml contains the necessary project configuration
  • No stack-specific configurations are required as the project uses a simple configuration with tags defined in the main Pulumi.yaml
  • The COPY command correctly includes all .go files and Pulumi.yaml which are the essential files needed
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for Pulumi configuration files in the directory
fd -t f "Pulumi.*\.yaml$" deployments/pulumi/ledger/

Length of output: 92


Script:

#!/bin/bash
# Check the content of Pulumi.yaml to understand the project configuration
cat deployments/pulumi/ledger/Pulumi.yaml

# Also check if there are any stack references in the Go files
rg "stack\." deployments/pulumi/ledger/ -A 2

Length of output: 217

deployments/pulumi/postgres/Earthfile (3)

8-10: Well-configured caching strategy

Excellent use of shared caching for Go modules, build cache, and linter cache. This will significantly improve build performance across runs.


1-2: Consider upgrading Earthly version and verify project name

Two potential concerns:

  1. Earthly version 0.8 is relatively old. Consider upgrading to the latest stable version for potential improvements and bug fixes.
  2. The project name is set to "FormanceHQ/ledger" but this file is in the "postgres" directory, which seems inconsistent.

34-34: 🛠️ Refactor suggestion

Review linting configuration

The current linting configuration has some potential issues:

  1. The 5-minute timeout might be insufficient for larger codebases
  2. Using --fix flag automatically might cause unexpected changes
  3. No explicit golangci-lint configuration file is specified
-    RUN golangci-lint run --fix --build-tags it --timeout 5m
+    COPY .golangci.yml .
+    RUN golangci-lint run --build-tags it --timeout 10m
test/rolling-upgrades/generator/Earthfile (3)

1-5: LGTM! Good version pinning practice.

The version configuration and core image import are well-defined with specific version tags, which is a good practice for build reproducibility.


23-31: LGTM! Well-structured tidy target.

The tidy target is well-configured with appropriate caching and artifact saving.


6-11: Verify cache effectiveness across builds.

The caching configuration looks good with appropriate sharing and specific IDs for different types of caches.

✅ Verification successful

Cache configuration is consistently implemented across the codebase

The verification shows that the cache configuration is effectively standardized across multiple Earthfiles:

  • Root Earthfile
  • test/rolling-upgrades/generator/Earthfile
  • test/rolling-upgrades/Earthfile
  • tools/generator/Earthfile
  • deployments/pulumi/postgres/Earthfile
  • deployments/pulumi/ledger/Earthfile

All files consistently use the same cache IDs and paths for Go modules, build cache, and golangci-lint cache, indicating a well-maintained caching strategy.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the cache directories are properly utilized in the build process

# Check for cache directories in .gitignore
echo "Verifying cache directories are properly ignored:"
rg -l "\.cache|go/pkg/mod" .gitignore

# Look for other Earthfiles using similar caching to ensure consistency
echo "Checking cache consistency across Earthfiles:"
fd Earthfile | xargs rg "CACHE.*sharing=shared.*go-mod-cache|CACHE.*sharing=shared.*go-cache|CACHE.*sharing=shared.*golangci-cache"

Length of output: 1931

deployments/pulumi/ledger/main.go (2)

1-9: LGTM! Well-structured imports and package declaration.

The imports are appropriate for a Pulumi configuration file, including necessary error handling packages and the Pulumi SDK.


6-6: Verify the ledger package import path.

Let's ensure the package path is correct and the package exists.

✅ Verification successful

The package import path is correct and properly structured

The verification confirms that:

  • The package exists at the correct location (deployments/pulumi/ledger/pkg)
  • The package is properly declared as pulumi_ledger
  • The import in main.go correctly references the package
  • The package is actively used to create the LedgerComponent with proper configuration
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify the existence of the ledger package and its component definition
fd -t f "component\.go$" "deployments/pulumi/ledger/pkg"

# Check the package declaration in the component file
rg -l "package pulumi_ledger" "deployments/pulumi/ledger/pkg"

Length of output: 204


Script:

#!/bin/bash
# Let's verify the package structure and imports
cat deployments/pulumi/ledger/pkg/component.go

# Also check the main.go file to understand how the package is used
cat deployments/pulumi/ledger/main.go

Length of output: 3959

test/rolling-upgrades/Earthfile (2)

1-1: LGTM: Version configuration enhancement

The addition of --wildcard-builds flag is appropriate for enabling flexible target matching, which aligns with the PR's objective of splitting Pulumi configurations.


24-26: Verify the existence of new source paths

The source paths have been updated to include generator and Pulumi deployment configurations. Let's verify these paths exist in the repository.

✅ Verification successful

Source paths verified and exist in the repository

All the referenced paths in the COPY commands exist in the repository structure:

  • ./generator
  • deployments/pulumi/ledger
  • deployments/pulumi/postgres
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence of source paths used in COPY commands

echo "Checking source paths..."
for path in "./generator" "deployments/pulumi/ledger" "deployments/pulumi/postgres"; do
  if fd -t d "^${path}$"; then
    echo "✓ Found: $path"
  else
    echo "✗ Missing: $path"
  fi
done

Length of output: 637

deployments/pulumi/ledger/pkg/component.go (1)

37-37: Verify the chart path is correct and accessible

Ensure that the relative path "../../../helm" correctly points to the Helm chart location. Relative paths can sometimes lead to issues if the directory structure changes.

Earthfile (1)

147-147: Verify wildcard usage in BUILD command

Using a wildcard * in the BUILD command may unintentionally include undesired directories or targets. Ensure that BUILD ./deployments/pulumi/*+pre-commit matches only the intended pre-commit targets within ./deployments/pulumi/. For greater clarity and control, consider specifying the exact directories.

Run the following script to list the directories matched by the wildcard:

✅ Verification successful

Let me verify if these directories have pre-commit targets by checking their Earthfiles.


Wildcard usage in BUILD command is appropriate

The wildcard usage is safe and intentional here. Both ./deployments/pulumi/ledger and ./deployments/pulumi/postgres directories contain Earthfiles with identical pre-commit targets that run tidy and lint builds. The wildcard pattern correctly matches these two directories, and there are no unintended matches.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: List directories matched by the wildcard in ./deployments/pulumi/

fd --type d --max-depth 1 '.' ./deployments/pulumi/

Length of output: 111


Script:

#!/bin/bash
# Check if both directories have Earthfiles and contain pre-commit targets
echo "=== Checking ledger/Earthfile ==="
cat ./deployments/pulumi/ledger/Earthfile 2>/dev/null | grep -A 5 "pre-commit:"

echo -e "\n=== Checking postgres/Earthfile ==="
cat ./deployments/pulumi/postgres/Earthfile 2>/dev/null | grep -A 5 "pre-commit:"

Length of output: 389

if image == "" {
image = "ghcr.io/formancehq/ledger-generator:latest"
}
ledgerURL := conf.Require("ledger-url")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add URL validation for ledger-url

The ledger-url is required but not validated. Consider adding URL format validation to catch configuration errors early.

 ledgerURL := conf.Require("ledger-url")
+if _, err := url.Parse(ledgerURL); err != nil {
+    return fmt.Errorf("invalid ledger-url format: %w", err)
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ledgerURL := conf.Require("ledger-url")
ledgerURL := conf.Require("ledger-url")
if _, err := url.Parse(ledgerURL); err != nil {
return fmt.Errorf("invalid ledger-url format: %w", err)
}

Comment on lines 39 to 41
pre-commit:
BUILD +tidy
BUILD +lint
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider enhancing pre-commit checks

The pre-commit target could benefit from additional validation steps:

  1. Running tests (if applicable)
  2. Validating Pulumi configuration
  3. Security scanning for infrastructure code
 pre-commit:
     BUILD +tidy
     BUILD +lint
+    # Add test target if applicable
+    BUILD +test
+    # Validate Pulumi configuration
+    RUN pulumi preview --stack dev --non-interactive

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 32 to 42
lint:
FROM +tidy
CACHE --id go-mod-cache /go/pkg/mod
CACHE --id go-cache /root/.cache/go-build
CACHE --id golangci-cache /root/.cache/golangci-lint

RUN golangci-lint run --fix --build-tags it --timeout 5m

SAVE ARTIFACT main.go AS LOCAL main.go
SAVE ARTIFACT pkg AS LOCAL pkg

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Reconsider using --fix flag in CI pipeline.

The --fix flag in golangci-lint automatically modifies files, which might not be desirable in a CI pipeline. Consider removing it to ensure the pipeline fails on lint errors instead of fixing them automatically.

-    RUN golangci-lint run --fix --build-tags it --timeout 5m
+    RUN golangci-lint run --build-tags it --timeout 5m
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
lint:
FROM +tidy
CACHE --id go-mod-cache /go/pkg/mod
CACHE --id go-cache /root/.cache/go-build
CACHE --id golangci-cache /root/.cache/golangci-lint
RUN golangci-lint run --fix --build-tags it --timeout 5m
SAVE ARTIFACT main.go AS LOCAL main.go
SAVE ARTIFACT pkg AS LOCAL pkg
lint:
FROM +tidy
CACHE --id go-mod-cache /go/pkg/mod
CACHE --id go-cache /root/.cache/go-build
CACHE --id golangci-cache /root/.cache/golangci-lint
RUN golangci-lint run --build-tags it --timeout 5m
SAVE ARTIFACT main.go AS LOCAL main.go
SAVE ARTIFACT pkg AS LOCAL pkg

Comment on lines 35 to 39
debug, _ := conf.TryBool("debug")
imagePullPolicy, _ := conf.Try("image.pullPolicy")

replicaCount, _ := conf.TryInt("replicaCount")
experimentalFeatures, _ := conf.TryBool("experimentalFeatures")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling consistency for optional configurations.

The error handling is inconsistent across optional configurations. Some errors are silently ignored which could lead to unexpected behavior.

Consider validating and logging when using default values:

-		debug, _ := conf.TryBool("debug")
-		imagePullPolicy, _ := conf.Try("image.pullPolicy")
-		replicaCount, _ := conf.TryInt("replicaCount")
-		experimentalFeatures, _ := conf.TryBool("experimentalFeatures")
+		debug, err := conf.TryBool("debug")
+		if err != nil && !errors.Is(err, config.ErrMissingVar) {
+			return fmt.Errorf("invalid debug configuration: %w", err)
+		}
+
+		imagePullPolicy, err := conf.Try("image.pullPolicy")
+		if err != nil && !errors.Is(err, config.ErrMissingVar) {
+			return fmt.Errorf("invalid imagePullPolicy configuration: %w", err)
+		}
+
+		replicaCount, err := conf.TryInt("replicaCount")
+		if err != nil && !errors.Is(err, config.ErrMissingVar) {
+			return fmt.Errorf("invalid replicaCount configuration: %w", err)
+		}
+		if replicaCount < 0 {
+			return fmt.Errorf("replicaCount must be non-negative")
+		}
+
+		experimentalFeatures, err := conf.TryBool("experimentalFeatures")
+		if err != nil && !errors.Is(err, config.ErrMissingVar) {
+			return fmt.Errorf("invalid experimentalFeatures configuration: %w", err)
+		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
debug, _ := conf.TryBool("debug")
imagePullPolicy, _ := conf.Try("image.pullPolicy")
replicaCount, _ := conf.TryInt("replicaCount")
experimentalFeatures, _ := conf.TryBool("experimentalFeatures")
debug, err := conf.TryBool("debug")
if err != nil && !errors.Is(err, config.ErrMissingVar) {
return fmt.Errorf("invalid debug configuration: %w", err)
}
imagePullPolicy, err := conf.Try("image.pullPolicy")
if err != nil && !errors.Is(err, config.ErrMissingVar) {
return fmt.Errorf("invalid imagePullPolicy configuration: %w", err)
}
replicaCount, err := conf.TryInt("replicaCount")
if err != nil && !errors.Is(err, config.ErrMissingVar) {
return fmt.Errorf("invalid replicaCount configuration: %w", err)
}
if replicaCount < 0 {
return fmt.Errorf("replicaCount must be non-negative")
}
experimentalFeatures, err := conf.TryBool("experimentalFeatures")
if err != nil && !errors.Is(err, config.ErrMissingVar) {
return fmt.Errorf("invalid experimentalFeatures configuration: %w", err)
}

Comment on lines 128 to 130

BUILD ./*+pre-commit
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Wildcard pre-commit build could trigger recursive builds

The ./*+pre-commit in test/rolling-upgrades/Earthfile will trigger pre-commit targets in subdirectories, specifically test/rolling-upgrades/generator/Earthfile. This creates a potential recursive build situation since:

  • The parent directory's pre-commit target will trigger the generator's pre-commit
  • Both files have identical pre-commit targets (+tidy, +lint)
  • This leads to duplicate and unnecessary builds

Recommendation:

  • Remove the ./*+pre-commit line to avoid recursive builds
  • Keep only the direct BUILD +tidy and BUILD +lint targets
🔗 Analysis chain

Verify the scope of wildcard builds

The addition of ./*+pre-commit will run pre-commit for all targets in the current directory. Let's verify what targets this might include to ensure we're not triggering unnecessary builds.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check what targets might be affected by the wildcard build

echo "Checking for other Earthfiles in the current directory..."
fd -t f "Earthfile$" . -x dirname {}

Length of output: 339


Script:

#!/bin/bash
# Let's check the content of these Earthfiles to see if they have pre-commit targets

echo "Checking for pre-commit targets in Earthfiles..."
for dir in $(fd -t f "Earthfile$" .); do
    echo "=== $dir ==="
    rg "pre-commit:" "$dir" -A 5
done

Length of output: 1939

Comment on lines 52 to 53
return nil, fmt.Errorf("installing release")
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Include error details when wrapping errors

When returning an error, include the original error for better context. Modify the return statement to:

-		return nil, fmt.Errorf("installing release")
+		return nil, fmt.Errorf("installing release: %w", err)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return nil, fmt.Errorf("installing release")
}
return nil, fmt.Errorf("installing release: %w", err)
}

Image pulumi.StringInput
}

func NewGeneratorComponent(ctx *pulumi.Context, name string, args *GeneratorComponentArgs, opts ...pulumi.ResourceOption) (*GeneratorComponent, error) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation for required input arguments

Currently, there is no validation to ensure that Namespace and LedgerURL are provided. Adding checks for these required inputs can prevent potential runtime errors.

Apply the following changes:

 func NewGeneratorComponent(ctx *pulumi.Context, name string, args *GeneratorComponentArgs, opts ...pulumi.ResourceOption) (*GeneratorComponent, error) {
+	if args == nil {
+		return nil, fmt.Errorf("args cannot be nil")
+	}
+	if args.Namespace == nil {
+		return nil, fmt.Errorf("Namespace is a required argument")
+	}
+	if args.LedgerURL == nil {
+		return nil, fmt.Errorf("LedgerURL is a required argument")
+	}
 	cmp := &GeneratorComponent{}
 	err := ctx.RegisterComponentResource("Formance:Ledger:Generator", name, cmp, opts...)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func NewGeneratorComponent(ctx *pulumi.Context, name string, args *GeneratorComponentArgs, opts ...pulumi.ResourceOption) (*GeneratorComponent, error) {
func NewGeneratorComponent(ctx *pulumi.Context, name string, args *GeneratorComponentArgs, opts ...pulumi.ResourceOption) (*GeneratorComponent, error) {
if args == nil {
return nil, fmt.Errorf("args cannot be nil")
}
if args.Namespace == nil {
return nil, fmt.Errorf("Namespace is a required argument")
}
if args.LedgerURL == nil {
return nil, fmt.Errorf("LedgerURL is a required argument")
}
cmp := &GeneratorComponent{}
err := ctx.RegisterComponentResource("Formance:Ledger:Generator", name, cmp, opts...)

Comment on lines 112 to 116
err = checkStack.Workspace().RemoveStack(ctx, stack.Name())
if err != nil {
t.Log(err)
return
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use 'checkStack.Name()' instead of 'stack.Name()' when removing the check stack

In the cleanup function for checkStack, the code calls stack.Name() instead of checkStack.Name(). This will cause it to attempt to remove the wrong stack, potentially leading to unexpected behavior.

Apply this diff to fix the issue:

err = checkStack.Workspace().RemoveStack(ctx, stack.Name())
- err = checkStack.Workspace().RemoveStack(ctx, stack.Name())
+ err = checkStack.Workspace().RemoveStack(ctx, checkStack.Name())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
err = checkStack.Workspace().RemoveStack(ctx, stack.Name())
if err != nil {
t.Log(err)
return
}
err = checkStack.Workspace().RemoveStack(ctx, checkStack.Name())
if err != nil {
t.Log(err)
return
}

Comment on lines 147 to 151
func deployStack(ctx *pulumi.Context) error {
stack, err := NewStackComponent(ctx, "full", &StackComponentArgs{
GeneratorImage: pulumi.String(config.Get(ctx, "generator:image")),
LedgerVersion: pulumi.String(config.Get(ctx, "ledger:version")),
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Set 'Namespace' in 'StackComponentArgs' to avoid nil reference

In the deployStack function, the Namespace field is not set when creating StackComponentArgs. Since Namespace is used in NewStackComponent, passing a nil value may lead to unexpected behavior or a nil pointer dereference when args.Namespace is accessed.

Apply this diff to set the Namespace field:

func deployStack(ctx *pulumi.Context) error {
    stack, err := NewStackComponent(ctx, "full", &StackComponentArgs{
        GeneratorImage: pulumi.String(config.Get(ctx, "generator:image")),
        LedgerVersion:  pulumi.String(config.Get(ctx, "ledger:version")),
+       Namespace:      pulumi.String("default"),
    })
    if err != nil {
        return err
    }

Alternatively, retrieve the namespace from the configuration if necessary.

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 119 to 123
ret, err := upAndPrintOutputs(ctx, checkStack, map[string]auto.ConfigValue{})
require.NoError(t, err, "upping check stack")

testFailure = ret.Outputs["phase"].Value.(string) == "Failed"
require.False(t, testFailure)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Check for existence of "phase" key in outputs before accessing

Accessing ret.Outputs["phase"].Value without ensuring the key exists may lead to a runtime panic if the key is missing. Ensure that the key exists before accessing its value to prevent a potential nil pointer dereference.

Apply this diff to check for the key's existence:

+ phaseOutput, ok := ret.Outputs["phase"]
+ require.True(t, ok, "'phase' output is missing in stack outputs")
+ phaseValue, ok := phaseOutput.Value.(string)
+ require.True(t, ok, "phase output value is not a string")
- testFailure = ret.Outputs["phase"].Value.(string) == "Failed"
+ testFailure = phaseValue == "Failed"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ret, err := upAndPrintOutputs(ctx, checkStack, map[string]auto.ConfigValue{})
require.NoError(t, err, "upping check stack")
testFailure = ret.Outputs["phase"].Value.(string) == "Failed"
require.False(t, testFailure)
ret, err := upAndPrintOutputs(ctx, checkStack, map[string]auto.ConfigValue{})
require.NoError(t, err, "upping check stack")
phaseOutput, ok := ret.Outputs["phase"]
require.True(t, ok, "'phase' output is missing in stack outputs")
phaseValue, ok := phaseOutput.Value.(string)
require.True(t, ok, "phase output value is not a string")
testFailure = phaseValue == "Failed"
require.False(t, testFailure)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Outside diff range and nitpick comments (5)
tools/dataset/pkg/rds.go (1)

57-57: Specify the exact engine version

Using "16" for EngineVersion might lead to unexpected upgrades. Specify the exact minor version to ensure consistency.

Apply this diff to specify the engine version:

-        EngineVersion:      pulumi.String("16"),
+        EngineVersion:      pulumi.String("16.0"),
tools/dataset/pkg/dataset.go (1)

88-109: Ensure dependencies are correctly set for snapshot creation

The cmp.Snapshot depends on cmp.Generator, but if cmp.Generator is nil, the DependsOn option might cause issues. Adjust the resource options accordingly.

Apply this diff to conditionally set DependsOn:

     if generator != nil {
         resourceOptions = append(resourceOptions, pulumi.DependsOn([]pulumi.Resource{generator}))
+    } else {
+        // Remove DependsOn if generator is nil
+        resourceOptions = resourceOptions
     }
tools/generator/pulumi/pkg/component.go (1)

39-45: Validate required input parameters earlier

The validation for untilLogID and script should occur before registering the component resource to fail fast if inputs are invalid.

Apply this diff to move the validation before resource registration:

+    if args.UntilLogID == nil {
+        return nil, errors.New("untilLogID is required")
+    }
+
+    if args.Script == nil {
+        return nil, errors.New("script is required")
+    }
+
     err := ctx.RegisterComponentResource("Formance:Ledger:Tools:Generator", name, cmp, opts...)
     if err != nil {
         return nil, err
     }
tools/generator/pulumi/Earthfile (1)

43-45: Consider adding tests to pre-commit target

The pre-commit target currently runs tidy and lint, but it would be beneficial to also run tests to catch potential issues early.

Apply this diff to add tests to pre-commit:

pre-commit:
    BUILD +tidy
    BUILD +lint
+   BUILD +test

+test:
+   FROM +sources
+   CACHE --id go-mod-cache /go/pkg/mod
+   CACHE --id go-cache /root/.cache/go-build
+   RUN go test ./...
tools/dataset/main.go (1)

35-35: Add context to error return

The error from NewDatasetComponent is returned without context, making it harder to debug issues.

Apply this diff to wrap the error with context:

-		return err
+		return fmt.Errorf("failed to create dataset component: %w", err)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between f0c054e and 6421ffb.

⛔ Files ignored due to path filters (8)
  • .github/workflows/dataset.yml is excluded by !**/*.yml
  • test/rolling-upgrades/go.mod is excluded by !**/*.mod
  • tools/dataset/Pulumi.yaml is excluded by !**/*.yaml
  • tools/dataset/go.mod is excluded by !**/*.mod
  • tools/dataset/go.sum is excluded by !**/*.sum, !**/*.sum
  • tools/generator/pulumi/Pulumi.yaml is excluded by !**/*.yaml
  • tools/generator/pulumi/go.mod is excluded by !**/*.mod
  • tools/generator/pulumi/go.sum is excluded by !**/*.sum, !**/*.sum
📒 Files selected for processing (9)
  • deployments/pulumi/ledger/pkg/component.go (1 hunks)
  • pkg/generate/set.go (2 hunks)
  • test/rolling-upgrades/main_test.go (4 hunks)
  • tools/dataset/main.go (1 hunks)
  • tools/dataset/pkg/dataset.go (1 hunks)
  • tools/dataset/pkg/rds.go (1 hunks)
  • tools/generator/pulumi/Earthfile (1 hunks)
  • tools/generator/pulumi/main.go (1 hunks)
  • tools/generator/pulumi/pkg/component.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • deployments/pulumi/ledger/pkg/component.go
🧰 Additional context used
🪛 golangci-lint (1.62.2)
tools/dataset/pkg/dataset.go

46-46: ineffectual assignment to err

(ineffassign)

test/rolling-upgrades/main_test.go

168-168: undefined: pulumi_generator

(typecheck)


201-201: cannot use args.LedgerVersion (variable of type pulumi.StringInput) as pulumix.Input[string] value in struct literal: pulumi.StringInput does not implement pulumix.Input[string] (missing method ToOutput)

(typecheck)


218-218: undefined: pulumi_generator

(typecheck)

🔇 Additional comments (3)
tools/generator/pulumi/pkg/component.go (1)

128-128: Ensure correct type conversion for Args

The type assertion for Args may fail if not properly handled. Confirm that generatorArgs resolves to the correct type.

Run the following script to check the type of generatorArgs:

✅ Verification successful

Based on the gathered information, I can now provide the final response:

Type conversion for Args is correctly handled

The type conversion is safe because:

  • generatorArgs is created using pulumix.Apply4Err which processes multiple inputs to generate a string array
  • The function explicitly returns []string which is compatible with pulumi.StringArrayOutput after going through ToOutput().Untyped()
  • The conversion chain follows Pulumi's type system conventions for converting native Go types to Pulumi outputs
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the type of generatorArgs in component.go

# Search for the definition of generatorArgs and check its type
ast-grep --pattern $'
func(...) {
    $$$
    generatorArgs := $*_
    $$$
}
' *.go

Length of output: 87


Script:

#!/bin/bash
# Let's try searching for generatorArgs in the specific file mentioned in the review
rg -A 5 -B 5 "generatorArgs" tools/generator/pulumi/pkg/component.go

Length of output: 898


Script:

#!/bin/bash
# Let's also check the type definition and usage context
ast-grep --pattern 'generatorArgs.ToOutput' tools/generator/pulumi/pkg/component.go

Length of output: 83


Script:

#!/bin/bash
# Let's look at the entire function context where this conversion happens
rg -A 10 -B 10 "Args:\s+generatorArgs\.ToOutput" tools/generator/pulumi/pkg/component.go

Length of output: 894


Script:

#!/bin/bash
# Let's check the definition of pulumix.Apply4Err to understand the return type
rg -A 5 "func Apply4Err" tools/generator/pulumi/pkg/pulumix/

Length of output: 138


Script:

#!/bin/bash
# Let's also check how generatorArgs is used in the rest of the function
rg -A 20 -B 10 "pulumix\.Apply4Err\(" tools/generator/pulumi/pkg/component.go

Length of output: 910

test/rolling-upgrades/main_test.go (2)

112-116: ⚠️ Potential issue

Fix stack name in cleanup function

The cleanup function is using the wrong stack name when removing the check stack.

Apply this diff to fix the issue:

-		err = checkStack.Workspace().RemoveStack(ctx, stack.Name())
+		err = checkStack.Workspace().RemoveStack(ctx, checkStack.Name())

8-10: ⚠️ Potential issue

Add missing pulumi_generator import

The code references pulumi_generator package but it's not imported.

Add the following import:

 import (
     pulumi_ledger "github.com/formancehq/ledger/deployments/pulumi/ledger/pkg"
     pulumi_postgres "github.com/formancehq/ledger/deployments/pulumi/postgres/pkg"
+    pulumi_generator "github.com/formancehq/ledger/tools/generator/pulumi/pkg"
     "github.com/formancehq/ledger/tools/generator/pulumi/pkg"

Likely invalid or redundant comment.

case components.V2BulkElementResultTypeRevertTransaction:
logID = r.V2BulkElementResultRevertTransaction.LogID
default:
panic(fmt.Sprintf("unexpected result type: %s", r.Type))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid using panic in production code

Using panic in production code is discouraged as it can crash the entire application. Instead, consider returning an error to handle unexpected result types gracefully.

Apply this diff to return an error instead of panicking:

-       panic(fmt.Sprintf("unexpected result type: %s", r.Type))
+       return acc

Then, handle the unexpected type appropriately by logging an error or returning it to the caller.

Committable suggestion skipped: line range outside the PR's diff.

if err != nil {
return fmt.Errorf("failed to list logs: %w", err)
}
if logs.V2LogsCursorResponse.Cursor.Data[0].ID.Cmp(big.NewInt(int64(s.untilLogID))) > 0 {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Prevent potential index out of range panic when accessing Data[0]

Before accessing logs.V2LogsCursorResponse.Cursor.Data[0], ensure that Data has at least one element to avoid a possible panic if the logs are empty.

Apply this diff to add a length check:

+       if len(logs.V2LogsCursorResponse.Cursor.Data) == 0 {
+           logging.FromContext(ctx).Info("No logs available, stopping generator")
+           return nil
+       }
        if logs.V2LogsCursorResponse.Cursor.Data[0].ID.Cmp(big.NewInt(int64(s.untilLogID))) > 0 {
            logging.FromContext(ctx).Infof("Log %s reached, stopping generator", logs.V2LogsCursorResponse.Cursor.Data[0].ID.String())
            return nil
        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if logs.V2LogsCursorResponse.Cursor.Data[0].ID.Cmp(big.NewInt(int64(s.untilLogID))) > 0 {
if len(logs.V2LogsCursorResponse.Cursor.Data) == 0 {
logging.FromContext(ctx).Info("No logs available, stopping generator")
return nil
}
if logs.V2LogsCursorResponse.Cursor.Data[0].ID.Cmp(big.NewInt(int64(s.untilLogID))) > 0 {
logging.FromContext(ctx).Infof("Log %s reached, stopping generator", logs.V2LogsCursorResponse.Cursor.Data[0].ID.String())
return nil
}

Comment on lines 35 to 36
masterUsername := pulumix.Val("root")
masterPassword := pulumix.Val("password")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid hardcoding database credentials

Storing sensitive information like masterUsername and masterPassword directly in the code is insecure. Consider retrieving these values from a secure source or using Pulumi's configuration management features.

Apply this diff to use Pulumi configuration for credentials:

-    masterUsername := pulumix.Val("root")
-    masterPassword := pulumix.Val("password")
+    conf := config.New(ctx, "")
+    masterUsername := pulumix.Val(conf.Require("dbUsername"))
+    masterPassword := pulumix.Val(conf.RequireSecret("dbPassword"))

Ensure that dbUsername and dbPassword are set securely in your Pulumi configuration.

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 46 to 71
cmp.Ledger, err = pulumi_ledger.NewLedgerComponent(ctx, "ledger", &pulumi_ledger.LedgerComponentArgs{
Timeout: pulumi.Int(30),
Tag: args.LedgerVersion,
ImagePullPolicy: pulumi.String("Always"),
PostgresURI: pulumi.Sprintf(
"postgres://%s:%s@%s:%d/postgres?sslmode=disable",
cmp.RDS.MasterUsername,
cmp.RDS.MasterPassword,
cmp.RDS.Endpoint,
cmp.RDS.Port,
),
ExperimentalFeatures: pulumi.Bool(true),
Namespace: args.Namespace,
}, pulumi.Transforms([]pulumi.ResourceTransform{
// Update relative location of the helm chart
func(context context.Context, args *pulumi.ResourceTransformArgs) *pulumi.ResourceTransformResult {
if args.Type == "kubernetes:helm.sh/v3:Release" {
args.Props["chart"] = pulumi.String("../../deployments/helm")
}

return &pulumi.ResourceTransformResult{
Props: args.Props,
}
},
}), pulumi.Parent(cmp))

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ineffectual assignment to err at line 46

The variable err is assigned but not used before the next assignment, potentially masking errors from pulumi_ledger.NewLedgerComponent.

Apply this diff to handle the error properly:

     cmp.Ledger, err = pulumi_ledger.NewLedgerComponent(ctx, "ledger", &pulumi_ledger.LedgerComponentArgs{
         Timeout:         pulumi.Int(30),
         Tag:             args.LedgerVersion,
         ImagePullPolicy: pulumi.String("Always"),
         PostgresURI: pulumi.Sprintf(
             "postgres://%s:%s@%s:%d/postgres?sslmode=disable",
             cmp.RDS.MasterUsername,
             cmp.RDS.MasterPassword,
             cmp.RDS.Endpoint,
             cmp.RDS.Port,
         ),
         ExperimentalFeatures: pulumi.Bool(true),
         Namespace:            args.Namespace,
     }, pulumi.Transforms([]pulumi.ResourceTransform{
         // Update relative location of the helm chart
         func(context context.Context, args *pulumi.ResourceTransformArgs) *pulumi.ResourceTransformResult {
             if args.Type == "kubernetes:helm.sh/v3:Release" {
                 args.Props["chart"] = pulumi.String("../../deployments/helm")
             }

             return &pulumi.ResourceTransformResult{
                 Props: args.Props,
             }
         },
     }), pulumi.Parent(cmp))
+    if err != nil {
+        return nil, fmt.Errorf("creating Ledger component: %w", err)
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cmp.Ledger, err = pulumi_ledger.NewLedgerComponent(ctx, "ledger", &pulumi_ledger.LedgerComponentArgs{
Timeout: pulumi.Int(30),
Tag: args.LedgerVersion,
ImagePullPolicy: pulumi.String("Always"),
PostgresURI: pulumi.Sprintf(
"postgres://%s:%s@%s:%d/postgres?sslmode=disable",
cmp.RDS.MasterUsername,
cmp.RDS.MasterPassword,
cmp.RDS.Endpoint,
cmp.RDS.Port,
),
ExperimentalFeatures: pulumi.Bool(true),
Namespace: args.Namespace,
}, pulumi.Transforms([]pulumi.ResourceTransform{
// Update relative location of the helm chart
func(context context.Context, args *pulumi.ResourceTransformArgs) *pulumi.ResourceTransformResult {
if args.Type == "kubernetes:helm.sh/v3:Release" {
args.Props["chart"] = pulumi.String("../../deployments/helm")
}
return &pulumi.ResourceTransformResult{
Props: args.Props,
}
},
}), pulumi.Parent(cmp))
cmp.Ledger, err = pulumi_ledger.NewLedgerComponent(ctx, "ledger", &pulumi_ledger.LedgerComponentArgs{
Timeout: pulumi.Int(30),
Tag: args.LedgerVersion,
ImagePullPolicy: pulumi.String("Always"),
PostgresURI: pulumi.Sprintf(
"postgres://%s:%s@%s:%d/postgres?sslmode=disable",
cmp.RDS.MasterUsername,
cmp.RDS.MasterPassword,
cmp.RDS.Endpoint,
cmp.RDS.Port,
),
ExperimentalFeatures: pulumi.Bool(true),
Namespace: args.Namespace,
}, pulumi.Transforms([]pulumi.ResourceTransform{
// Update relative location of the helm chart
func(context context.Context, args *pulumi.ResourceTransformArgs) *pulumi.ResourceTransformResult {
if args.Type == "kubernetes:helm.sh/v3:Release" {
args.Props["chart"] = pulumi.String("../../deployments/helm")
}
return &pulumi.ResourceTransformResult{
Props: args.Props,
}
},
}), pulumi.Parent(cmp))
if err != nil {
return nil, fmt.Errorf("creating Ledger component: %w", err)
}
🧰 Tools
🪛 golangci-lint (1.62.2)

46-46: ineffectual assignment to err

(ineffassign)

Comment on lines 17 to 20
image := conf.Get("image")
if image == "" {
image = "ghcr.io/formancehq/ledger-generator:latest"
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use consistent image versioning

The image variable is defaulting to "ghcr.io/formancehq/ledger-generator:latest", but later, the Version field seems to expect a version tag, not the full image name.

Apply this diff to correct the image version assignment:

     image := conf.Get("image")
     if image == "" {
-        image = "ghcr.io/formancehq/ledger-generator:latest"
+        image = "latest"
     }

Ensure that the Version parameter in GeneratorComponentArgs receives only the version tag.

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 14 to 23
Namespace: pulumi.String(config.Get(ctx, "namespace")),
RDS: pulumi_dataset_init_stack.RDSComponentArgs{
InstanceClass: pulumi.String(config.Get(ctx, "rds-instance-class")),
DBSubnetGroupName: pulumi.String(config.Require(ctx, "rds-db-subnet-group-name")),
InitializationSnapshot: pulumi.String(config.Get(ctx, "rds-initialization-snapshot")),
},
GeneratorVersion: pulumi.String(config.Get(ctx, "generator-version")),
UntilLogID: pulumi.Int(config.GetInt(ctx, "until-log-id")),
CreateSnapshot: pulumi.Bool(config.GetBool(ctx, "create-snapshot")),
Script: pulumi.String(config.Require(ctx, "script")),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for optional configuration values

The code uses config.Get for optional values but doesn't handle the case when they're empty. Consider using config.GetBool with default values for boolean configs and validate other optional configs.

Apply this diff to improve error handling:

-			Namespace: pulumi.String(config.Get(ctx, "namespace")),
+			Namespace: pulumi.String(config.GetString(ctx, "namespace", "default")),
-			GeneratorVersion: pulumi.String(config.Get(ctx, "generator-version")),
+			GeneratorVersion: pulumi.String(config.GetString(ctx, "generator-version", "latest")),
-			UntilLogID:       pulumi.Int(config.GetInt(ctx, "until-log-id")),
+			UntilLogID:       pulumi.Int(config.GetInt(ctx, "until-log-id", 0)),

Committable suggestion skipped: line range outside the PR's diff.


// Let a moment ensure the test image is actually sending requests
// We could maybe find a dynamic way to do that
<-time.After(10 * time.Second)
<-time.After(5 * time.Second)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Replace hardcoded delays with dynamic checks

The code uses hardcoded delays (time.After) to wait for test image readiness.

Consider implementing a dynamic readiness check:

-	<-time.After(5 * time.Second)
+	err = waitForPodReady(ctx, stack, stackOutputs["generator:pod-name"].Value.(string))
+	require.NoError(t, err, "waiting for test pod to be ready")

func waitForPodReady(ctx context.Context, stack auto.Stack, podName string) error {
    deadline := time.Now().Add(30 * time.Second)
    for time.Now().Before(deadline) {
        pod, err := corev1.GetPod(ctx, podName)
        if err != nil {
            return err
        }
        if pod.Status.Phase().Elem() == "Running" {
            return nil
        }
        time.Sleep(time.Second)
    }
    return fmt.Errorf("pod %s not ready after timeout", podName)
}

Also applies to: 75-75

Comment on lines 184 to 191
cmp.PostgresComponent, err = pulumi_postgres.NewPostgresComponent(
ctx,
"test",
&corev1.PodArgs{
Metadata: metav1.ObjectMetaArgs{
Namespace: pulumi.String(namespace),
},
Spec: corev1.PodSpecArgs{
RestartPolicy: pulumi.String("Never"),
Containers: corev1.ContainerArray{
corev1.ContainerArgs{
Name: pulumi.String("test"),
Args: generatorArgs,
Image: pulumi.String(image),
ImagePullPolicy: pulumi.String("Always"),
},
},
},
},
pulumi.Timeouts(&pulumi.CustomTimeouts{
Create: "10s",
Update: "10s",
Delete: "10s",
}),
pulumi.DeleteBeforeReplace(true),
"postgres",
&pulumi_postgres.PostgresComponentArgs{},
pulumi.Parent(cmp),
)
if err != nil {
return err
return nil, fmt.Errorf("creating postgres component: %w", err)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid hardcoding PostgreSQL configuration

The PostgreSQL component is created with empty arguments, potentially missing important configuration options.

Consider parameterizing the PostgreSQL configuration:

+type PostgresConfig struct {
+    Username    string
+    Password    string
+    Database    string
+    Port        int
+}

 	cmp.PostgresComponent, err = pulumi_postgres.NewPostgresComponent(
 		ctx,
 		"postgres",
-		&pulumi_postgres.PostgresComponentArgs{},
+		&pulumi_postgres.PostgresComponentArgs{
+			Username: config.GetString(ctx, "postgres:username", "postgres"),
+			Password: config.RequireSecret(ctx, "postgres:password"),
+			Database: config.GetString(ctx, "postgres:database", "ledger"),
+			Port:     config.GetInt(ctx, "postgres:port", 5432),
+		},
 		pulumi.Parent(cmp),
 	)

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 194 to 202
cmp.LedgerComponent, err = pulumi_ledger.NewLedgerComponent(ctx, "ledger", &pulumi_ledger.LedgerComponentArgs{
ImagePullPolicy: pulumi.String("Always"),
PostgresURI: pulumi.Sprintf("postgres://postgres:postgres@%s.svc.cluster.local:5432/ledger?sslmode=disable", cmp.PostgresComponent.Service),
Debug: pulumi.Bool(true),
ReplicaCount: pulumi.Int(1),
ExperimentalFeatures: pulumi.Bool(true),
Timeout: pulumi.Int(30),
Tag: args.LedgerVersion,
}, pulumi.Transforms([]pulumi.ResourceTransform{
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix type mismatch in LedgerComponent configuration

The Tag field expects pulumix.Input[string] but receives pulumi.StringInput.

Apply this diff to fix the type mismatch:

-		Tag:                  args.LedgerVersion,
+		Tag:                  pulumix.ToInput(args.LedgerVersion),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cmp.LedgerComponent, err = pulumi_ledger.NewLedgerComponent(ctx, "ledger", &pulumi_ledger.LedgerComponentArgs{
ImagePullPolicy: pulumi.String("Always"),
PostgresURI: pulumi.Sprintf("postgres://postgres:postgres@%s.svc.cluster.local:5432/ledger?sslmode=disable", cmp.PostgresComponent.Service),
Debug: pulumi.Bool(true),
ReplicaCount: pulumi.Int(1),
ExperimentalFeatures: pulumi.Bool(true),
Timeout: pulumi.Int(30),
Tag: args.LedgerVersion,
}, pulumi.Transforms([]pulumi.ResourceTransform{
cmp.LedgerComponent, err = pulumi_ledger.NewLedgerComponent(ctx, "ledger", &pulumi_ledger.LedgerComponentArgs{
ImagePullPolicy: pulumi.String("Always"),
PostgresURI: pulumi.Sprintf("postgres://postgres:postgres@%s.svc.cluster.local:5432/ledger?sslmode=disable", cmp.PostgresComponent.Service),
Debug: pulumi.Bool(true),
ReplicaCount: pulumi.Int(1),
ExperimentalFeatures: pulumi.Bool(true),
Timeout: pulumi.Int(30),
Tag: pulumix.ToInput(args.LedgerVersion),
}, pulumi.Transforms([]pulumi.ResourceTransform{
🧰 Tools
🪛 golangci-lint (1.62.2)

201-201: cannot use args.LedgerVersion (variable of type pulumi.StringInput) as pulumix.Input[string] value in struct literal: pulumi.StringInput does not implement pulumix.Input[string] (missing method ToOutput)

(typecheck)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Outside diff range and nitpick comments (15)
tools/dataset/pkg/dataset.go (4)

8-9: Consider using more descriptive import aliases

The v1 and v2 aliases could be more descriptive to improve code readability. Consider using k8score and k8smeta instead.

-	v1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/core/v1"
-	v2 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/meta/v1"
+	k8score "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/core/v1"
+	k8smeta "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/meta/v1"

14-30: Add field documentation for better code maintainability

Consider adding documentation for the struct fields to improve code maintainability and make it easier for other developers to understand the purpose of each field.

 type DatasetComponent struct {
 	pulumi.ResourceState
+	// RDS represents the RDS database component
 	RDS       *RDSComponent
+	// Ledger represents the ledger component
 	Ledger    *pulumi_ledger.LedgerComponent
+	// Generator represents the optional generator component
 	Generator pulumix.Output[*pulumi_generator.GeneratorComponent]
+	// Snapshot represents the optional RDS cluster snapshot
 	Snapshot  pulumix.Output[*rds.ClusterSnapshot]
 }

 type DatasetComponentArgs struct {
+	// Namespace is the Kubernetes namespace where components will be deployed
 	Namespace        pulumix.Input[string]
+	// RDS contains the configuration for the RDS component
 	RDS              RDSComponentArgs
+	// LedgerVersion specifies the version of the ledger to deploy
 	LedgerVersion    pulumix.Input[string]
+	// GeneratorVersion specifies the version of the generator to deploy
 	GeneratorVersion pulumix.Input[string]
+	// UntilLogID specifies the log ID to generate up to
 	UntilLogID       pulumix.Input[int]
+	// CreateSnapshot indicates whether to create an RDS snapshot
 	CreateSnapshot   pulumix.Input[bool]
+	// Script contains the generator script to execute
 	Script           pulumix.Input[string]
 }

84-84: Address the TODO comment about log checking

The TODO comment indicates a potential optimization to avoid unnecessary generator runs. This should be addressed to improve efficiency.

Would you like me to help implement the log checking functionality or create a GitHub issue to track this task?


102-118: Consider simplifying snapshot creation logic

The snapshot creation logic contains nested conditions and resource option modifications. Consider extracting this into a separate function for better readability and maintainability.

+func createClusterSnapshot(ctx *pulumi.Context, args *DatasetComponentArgs, cmp *DatasetComponent, generator *pulumi_generator.GeneratorComponent, baseResourceOptions []pulumi.ResourceOption) (*rds.ClusterSnapshot, error) {
+	if !createSnapshot {
+		return nil, nil
+	}
+
+	resourceOptions := append(baseResourceOptions, pulumi.RetainOnDelete(true))
+	if generator != nil {
+		resourceOptions = append(resourceOptions, pulumi.DependsOn([]pulumi.Resource{generator}))
+	}
+
+	return rds.NewClusterSnapshot(ctx, fmt.Sprintf("snapshot-%d", args.UntilLogID), &rds.ClusterSnapshotArgs{
+		DbClusterIdentifier:         cmp.RDS.Cluster.ClusterIdentifier,
+		DbClusterSnapshotIdentifier: pulumi.Sprintf("%s-%d", cmp.RDS.Cluster.ClusterIdentifier, args.UntilLogID),
+	},
+		resourceOptions...,
+	)
+}

Then use it in the main function:

-	cmp.Snapshot = pulumix.Apply2Err(args.CreateSnapshot, cmp.Generator, func(createSnapshot bool, generator *pulumi_generator.GeneratorComponent) (*rds.ClusterSnapshot, error) {
-		if !createSnapshot {
-			return nil, nil
-		}
-
-		resourceOptions := append(resourceOptions, pulumi.RetainOnDelete(true))
-		if generator != nil {
-			resourceOptions = append(resourceOptions, pulumi.DependsOn([]pulumi.Resource{generator}))
-		}
-
-		return rds.NewClusterSnapshot(ctx, fmt.Sprintf("snapshot-%d", args.UntilLogID), &rds.ClusterSnapshotArgs{
-			DbClusterIdentifier:         cmp.RDS.Cluster.ClusterIdentifier,
-			DbClusterSnapshotIdentifier: pulumi.Sprintf("%s-%d", cmp.RDS.Cluster.ClusterIdentifier, args.UntilLogID),
-		},
-			resourceOptions...,
-		)
-	})
+	cmp.Snapshot = pulumix.Apply2Err(args.CreateSnapshot, cmp.Generator, func(createSnapshot bool, generator *pulumi_generator.GeneratorComponent) (*rds.ClusterSnapshot, error) {
+		return createClusterSnapshot(ctx, args, cmp, generator, resourceOptions)
+	})
tools/generator/pulumi/pkg/component.go (5)

39-41: Combine Validation of Required Inputs for Clarity

Currently, the validation of args.UntilLogID and args.Script are separate. Consider combining these checks for more concise code.

Apply this diff to combine the input validations:

-if args.UntilLogID == nil {
-    return nil, errors.New("untilLogID is required")
-}
-
-if args.Script == nil {
-    return nil, errors.New("script is required")
-}
+if args.UntilLogID == nil || args.Script == nil {
+    return nil, errors.New("untilLogID and script are required")
+}

Also applies to: 43-45


47-53: Simplify Error Handling in ApplyErr Functions

The ApplyErr functions for untilLogID and script perform checks that could be consolidated to streamline error handling.

Consider simplifying the code as follows:

-untilLogID := pulumix.ApplyErr(args.UntilLogID, func(untilLogID int) (int, error) {
-    if untilLogID == 0 {
-        return 0, errors.New("untilLogID must be greater than 0")
-    }
-    return untilLogID, nil
-})
+untilLogID := pulumix.ApplyErr(args.UntilLogID, func(untilLogID int) (int, error) {
+    if untilLogID <= 0 {
+        return 0, errors.New("untilLogID must be greater than 0")
+    }
+    return untilLogID, nil
+})

-script := pulumix.ApplyErr(args.Script, func(script string) (string, error) {
-    if script == "" {
-        return "", errors.New("script is required")
-    }
-    return script, nil
-})
+script := args.Script

Since you've already checked for args.Script == nil, you may not need to validate if the script is empty again unless empty strings are considered invalid.

Also applies to: 55-61


89-92: Document the Default Value for VUs

The default value for VUs (virtual users) is set to 30. Consider documenting this default to improve code readability.

Adding a comment explaining the default value can help future maintainers understand the choice.


94-111: Preallocate Slice Capacity for generatorArgs

When building generatorArgs, preallocating the slice with an estimated capacity can enhance performance.

Apply this diff to preallocate the slice capacity:

 func(ledgerURL string, features map[string]string, vus, untilLogID int) ([]string, error) {
-    ret := make([]string, 0)
+    estimatedArgs := len(features)*2 + 6
+    ret := make([]string, 0, estimatedArgs)
     for key, value := range features {
         ret = append(ret, "--ledger-feature", key+"="+value)
     }
     ret = append(ret,
         ledgerURL,
         "/scripts/script.js",
         "-p", fmt.Sprint(vus),
         "--until-log-id", fmt.Sprint(untilLogID))
     return ret, nil
 },

This allocates sufficient capacity for the slice upfront, reducing the need for reallocation.


117-119: Remove Unnecessary Commented-Out Code

There is commented-out code for annotations. If it's not needed, consider removing it to keep the codebase clean.

Cleaning up commented code helps maintain readability.

deployments/pulumi/ledger/pkg/component.go (6)

23-23: Use 'Timeout' parameter in probe configurations

The Timeout parameter is defined in LedgerComponentArgs but is not used in the LivenessProbe and ReadinessProbe configurations. Including TimeoutSeconds allows for customizable probe timeouts, improving health check reliability.

Apply this diff to incorporate Timeout into the probes:

v3.LivenessProbeArgs{
     HttpGet: v3.HTTPGetActionArgs{
         Path: pulumi.String("/_healthcheck"),
         Port: pulumi.String("http"),
     },
+    TimeoutSeconds: args.Timeout.ToIntPtrOutput(),
},
v3.ReadinessProbeArgs{
     HttpGet: v3.HTTPGetActionArgs{
         Path: pulumi.String("/_healthcheck"),
         Port: pulumi.String("http"),
     },
+    TimeoutSeconds: args.Timeout.ToIntPtrOutput(),
},

Ensure that args.Timeout has a reasonable default value.

Also applies to: 113-124


135-142: Simplify boolean to string conversion for environment variables

Converting boolean values to strings for the DEBUG and EXPERIMENTAL_FEATURES environment variables can be simplified using strconv.FormatBool, enhancing readability.

Apply this diff to simplify the conversions:

+import "strconv"

v3.EnvVarArgs{
     Name: pulumi.String("DEBUG"),
-    Value: pulumix.Apply(debug, func(debug bool) string {
-        if debug {
-            return "true"
-        }
-        return "false"
-    }).Untyped().(pulumi.StringOutput),
+    Value: pulumix.Apply(debug, func(debug bool) string {
+        return strconv.FormatBool(debug)
+    }).Untyped().(pulumi.StringOutput),
},
v3.EnvVarArgs{
     Name: pulumi.String("EXPERIMENTAL_FEATURES"),
-    Value: pulumix.Apply(experimentalFeatures, func(experimentalFeatures bool) string {
-        if experimentalFeatures {
-            return "true"
-        }
-        return "false"
-    }).Untyped().(pulumi.StringOutput),
+    Value: pulumix.Apply(experimentalFeatures, func(experimentalFeatures bool) string {
+        return strconv.FormatBool(experimentalFeatures)
+    }).Untyped().(pulumi.StringOutput),
},

Remember to import "strconv" at the top of the file.

Also applies to: 145-151


70-75: Simplify tag defaulting logic

The logic for defaulting the tag value can be simplified using pulumix.ApplyOrDefault, improving code clarity.

Consider this simplified version:

- tag = pulumix.Apply(args.Tag, func(tag string) string {
-     if tag == "" {
-         return "latest"
-     }
-     return tag
- })
+ tag = pulumix.ApplyOrDefault(args.Tag, "latest")

This assumes that ApplyOrDefault applies the default value if args.Tag is nil or empty.


153-156: Add clarification for 'GRACE_PERIOD' environment variable

There's a comment referencing an article, but it's not immediately clear how GRACE_PERIOD is used by the application. Adding a brief explanation about its purpose would improve code readability.

Consider adding a comment like:

// GRACE_PERIOD sets the duration for the server to wait before shutting down to handle ongoing requests gracefully.

189-203: Simplify the construction of 'ServiceInternalURL'

The construction of ServiceInternalURL can be simplified by removing the unnecessary Apply since all values are readily available.

Apply this diff:

- cmp.ServiceInternalURL = pulumix.Apply(pulumi.Sprintf(
+ cmp.ServiceInternalURL = pulumi.Sprintf(
     "http://%s.%s.svc.cluster.local:%d",
     cmp.ServiceName,
     cmp.ServiceNamespace,
     cmp.ServicePort,
- ), func(url string) string {
-     return url
- })
+ )

This makes the code more concise and easier to read.


82-82: Define label keys as constants to avoid repetition

The label key "com.formance.stack/app" is hardcoded in multiple places. Defining it as a constant reduces the risk of typos and makes future updates easier.

Add a constant at the top of the file:

const appLabelKey = "com.formance.stack/app"

Then update the labels:

-     "com.formance.stack/app": pulumi.String("ledger"),
+     appLabelKey: pulumi.String("ledger"),

Also applies to: 95-95

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6421ffb and e28a9b9.

⛔ Files ignored due to path filters (9)
  • .github/workflows/dataset.yml is excluded by !**/*.yml
  • deployments/helm/Chart.yaml is excluded by !**/*.yaml
  • deployments/helm/templates/deployment.yaml is excluded by !**/*.yaml
  • deployments/helm/templates/hpa.yaml is excluded by !**/*.yaml
  • deployments/helm/templates/ingress.yaml is excluded by !**/*.yaml
  • deployments/helm/templates/service.yaml is excluded by !**/*.yaml
  • deployments/helm/templates/serviceaccount.yaml is excluded by !**/*.yaml
  • deployments/helm/templates/tests/test-connection.yaml is excluded by !**/*.yaml
  • deployments/helm/values.yaml is excluded by !**/*.yaml
📒 Files selected for processing (10)
  • deployments/helm/.helmignore (0 hunks)
  • deployments/helm/Earthfile (0 hunks)
  • deployments/helm/README.md (0 hunks)
  • deployments/helm/templates/NOTES.txt (0 hunks)
  • deployments/helm/templates/_helpers.tpl (0 hunks)
  • deployments/pulumi/ledger/pkg/component.go (1 hunks)
  • tools/dataset/main.go (1 hunks)
  • tools/dataset/pkg/dataset.go (1 hunks)
  • tools/dataset/pkg/rds.go (1 hunks)
  • tools/generator/pulumi/pkg/component.go (1 hunks)
💤 Files with no reviewable changes (5)
  • deployments/helm/README.md
  • deployments/helm/.helmignore
  • deployments/helm/Earthfile
  • deployments/helm/templates/NOTES.txt
  • deployments/helm/templates/_helpers.tpl
🚧 Files skipped from review as they are similar to previous changes (1)
  • tools/dataset/main.go
🧰 Additional context used
🪛 golangci-lint (1.62.2)
tools/dataset/pkg/dataset.go

67-67: ineffectual assignment to err

(ineffassign)

🔇 Additional comments (6)
tools/dataset/pkg/dataset.go (1)

67-82: ⚠️ Potential issue

Add error handling for NewLedgerComponent

The error returned from NewLedgerComponent is not being checked. This is a critical issue that could mask potential errors during component creation.

 	cmp.Ledger, err = pulumi_ledger.NewLedgerComponent(ctx, "ledger", &pulumi_ledger.LedgerComponentArgs{
 		Timeout:         pulumi.Int(30),
 		Tag:             args.LedgerVersion,
 		ImagePullPolicy: pulumi.String("Always"),
 		PostgresURI: pulumi.Sprintf(
 			"postgres://%s:%s@%s:%d/postgres?sslmode=disable",
 			cmp.RDS.MasterUsername,
 			cmp.RDS.MasterPassword,
 			cmp.RDS.PrimaryInstance.Endpoint,
 			cmp.RDS.PrimaryInstance.Port,
 		),
 		ExperimentalFeatures: pulumi.Bool(true),
 		Namespace:            args.Namespace,
 	},
 		resourceOptions...,
 	)
+	if err != nil {
+		return nil, fmt.Errorf("creating Ledger component: %w", err)
+	}
🧰 Tools
🪛 golangci-lint (1.62.2)

67-67: ineffectual assignment to err

(ineffassign)

tools/dataset/pkg/rds.go (1)

34-35: ⚠️ Potential issue

Avoid hardcoding database credentials

Storing sensitive information like masterUsername and masterPassword directly in the code is insecure. Consider retrieving these values from a secure source or using Pulumi's configuration features.

Apply this diff to use Pulumi configuration for credentials:

+	import "github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
+
+	conf := config.New(ctx, "")
-	masterUsername := pulumix.Val("root")
-	masterPassword := pulumix.Val("password")
+	masterUsername := pulumix.Val(conf.Require("dbUsername"))
+	masterPassword := pulumix.Val(conf.RequireSecret("dbPassword"))

Ensure that dbUsername and dbPassword are set securely in your Pulumi configuration.

tools/generator/pulumi/pkg/component.go (4)

63-71: Ensure Consistent Defaulting of Optional Inputs

The default value for version is set to "latest" if not provided. This approach is consistent and clear.


73-76: Validate Namespace Value

Currently, the namespace defaults to an empty string if not provided. Verify that an empty namespace is acceptable in your Kubernetes context.

If a namespace is required for resource creation, consider adding validation to ensure it is provided.


157-159: Register Component Outputs If Necessary

Currently, no outputs are registered for the component. If the component has outputs that should be exposed, ensure they are registered.

If there are outputs like JobNamespace, JobName, or JobID that consumers of this component might need, consider registering them:

if err := ctx.RegisterResourceOutputs(cmp, pulumi.Map{
    "jobNamespace": cmp.JobNamespace,
    "jobName":      cmp.JobName,
    "jobID":        cmp.JobID,
}); err != nil {
    return nil, fmt.Errorf("registering outputs: %w", err)
}

78-87: ⚠️ Potential issue

Handle Errors from ConfigMap Creation

Ensure that errors returned from v1.NewConfigMap are properly handled to prevent unexpected failures.

Modify the code to handle the error:

-scriptConfigMap := pulumix.ApplyErr(script, func(script string) (*v1.ConfigMap, error) {
-    return v1.NewConfigMap(ctx, "generator-script", &v1.ConfigMapArgs{
+scriptConfigMap := pulumix.ApplyErr(script, func(script string) (*v1.ConfigMap, error) {
+    configMap, err := v1.NewConfigMap(ctx, "generator-script", &v1.ConfigMapArgs{
         // existing arguments
     }, pulumi.Parent(cmp))
+    if err != nil {
+        return nil, err
+    }
+    return configMap, nil
 })

This ensures that any errors during ConfigMap creation are propagated correctly.

Likely invalid or redundant comment.

Comment on lines 93 to 95
"masterUsername": masterUsername,
"masterPassword": masterPassword,
}); err != nil {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid exposing sensitive data in resource outputs

Registering masterPassword as an output may inadvertently expose it. Ensure that sensitive information is handled securely and consider removing it from the outputs.

Apply this diff to remove the password from the outputs:

	if err := ctx.RegisterResourceOutputs(cmp, pulumi.Map{
		"masterUsername": masterUsername,
-		"masterPassword": masterPassword,
	}); err != nil {
		return nil, fmt.Errorf("registering outputs: %w", err)
	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"masterUsername": masterUsername,
"masterPassword": masterPassword,
}); err != nil {
"masterUsername": masterUsername,
}); err != nil {

Containers: v1.ContainerArray{
v1.ContainerArgs{
Name: pulumi.String("test"),
Args: generatorArgs.ToOutput(ctx.Context()).Untyped().(pulumi.StringArrayOutput),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure Correct Type Assertion for generatorArgs

The type assertion to pulumi.StringArrayOutput may fail if generatorArgs is not of the expected type. Verify that the conversion is safe.

Consider using .ToStringArrayOutput() for a safer conversion:

-Args: generatorArgs.ToOutput(ctx.Context()).Untyped().(pulumi.StringArrayOutput),
+Args: generatorArgs.ToStringArrayOutput(),

This ensures type safety and prevents potential runtime panics.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Args: generatorArgs.ToOutput(ctx.Context()).Untyped().(pulumi.StringArrayOutput),
Args: generatorArgs.ToStringArrayOutput(),

ImagePullPolicy pulumix.Input[string]
PostgresURI pulumix.Input[string]
Debug pulumix.Input[bool]
ReplicaCount pulumix.Input[int]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use the 'ReplicaCount' argument in Deployment specification

The ReplicaCount parameter is defined in LedgerComponentArgs but is not used when setting the number of replicas in the deployment. Currently, the replicas are hardcoded to 1.

Apply this diff to utilize ReplicaCount in the deployment:

v1.DeploymentSpecArgs{
-    Replicas: pulumi.Int(1),
+    Replicas: args.ReplicaCount.ToIntPtrOutput(),
     Selector: &v2.LabelSelectorArgs{

Ensure that args.ReplicaCount is properly set and has a default value if necessary.

Also applies to: 86-86

Namespace pulumix.Input[string]
Timeout pulumix.Input[int]
Tag pulumix.Input[string]
ImagePullPolicy pulumix.Input[string]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Include 'ImagePullPolicy' in Container specification

The ImagePullPolicy parameter is defined in LedgerComponentArgs but is not used in the container configuration. Specifying ImagePullPolicy controls how images are pulled and can be important in different deployment environments.

Apply this diff to include ImagePullPolicy in the container:

v3.ContainerArgs{
     Name:  pulumi.String("ledger"),
     Image: pulumi.Sprintf("ghcr.io/formancehq/ledger:%s", tag),
+    ImagePullPolicy: args.ImagePullPolicy.ToStringPtrOutput(),

Ensure that args.ImagePullPolicy is provided and valid.

Also applies to: 102-102

Env: v3.EnvVarArray{
v3.EnvVarArgs{
Name: pulumi.String("POSTGRES_URI"),
Value: postgresURI.Untyped().(pulumi.StringOutput),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid using 'Untyped()' with type assertions

Using Untyped().(pulumi.StringOutput) can be unsafe and may lead to runtime panics if the type assertion fails. Consider using ToOutput() methods or directly working with the appropriate types.

Apply this diff to use proper type conversions:

v3.EnvVarArgs{
     Name:  pulumi.String("POSTGRES_URI"),
-    Value: postgresURI.Untyped().(pulumi.StringOutput),
+    Value: postgresURI.Output(),
},
v3.EnvVarArgs{
     Name:  pulumi.String("GRACE_PERIOD"),
-    Value: gracePeriod.Untyped().(pulumi.StringOutput),
+    Value: gracePeriod.Output(),
},

Ensure that postgresURI and gracePeriod are of type pulumix.Output[string] and that Output() returns a pulumi.StringOutput.

Also applies to: 155-155

Comment on lines 45 to 51
postgresURI := pulumix.ApplyErr(args.PostgresURI, func(postgresURI string) (string, error) {
if postgresURI == "" {
return "", fmt.Errorf("postgresURI is required")
}

return postgresURI, nil
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle errors from 'postgresURI' validation before usage

The postgresURI is validated using pulumix.ApplyErr, but any resulting error is not checked before postgresURI is used in the environment variable. This could lead to runtime issues if postgresURI is invalid.

Add error handling after postgresURI assignment:

postgresURI := pulumix.ApplyErr(args.PostgresURI, func(postgresURI string) (string, error) {
    if postgresURI == "" {
        return "", fmt.Errorf("postgresURI is required")
    }
    return postgresURI, nil
})
+ if err := postgresURI.Err(); err != nil {
+     return nil, err
+ }

This ensures that any errors are caught before proceeding.

Also applies to: 128-128

@gfyrag gfyrag force-pushed the refacto/rolling-upgrades-tests branch 19 times, most recently from 71e6159 to f42d1db Compare December 3, 2024 15:16
@gfyrag gfyrag force-pushed the refacto/rolling-upgrades-tests branch 12 times, most recently from 41ac3bb to 357b3e8 Compare December 3, 2024 17:35
@gfyrag gfyrag force-pushed the refacto/rolling-upgrades-tests branch 2 times, most recently from 46c2b7f to f45c7ad Compare December 3, 2024 18:36
@gfyrag gfyrag force-pushed the refacto/rolling-upgrades-tests branch from 31726f1 to 8298be8 Compare December 4, 2024 18:00
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (6)
deployments/pulumi/pkg/component.go (1)

51-53: Handle missing PostgresURI more gracefully

The current implementation returns an error if PostgresURI is not provided. Consider providing a more descriptive error message or setting a default value if appropriate.

Apply this diff to improve the error handling:

 if args.PostgresURI == nil {
-    return nil, ErrPostgresURIRequired
+    return nil, fmt.Errorf("PostgresURI is required but was not provided")
 }
deployments/pulumi/Earthfile (3)

8-11: Optimize caching for Go builds and dependencies

Consider combining the cache directives for better cache utilization and to reduce redundancy.

Example:

 CACHE --sharing=shared --id go-mod-cache /go/pkg/mod
 CACHE --sharing=shared --id go-cache /root/.cache/go-build
 CACHE --sharing=shared --id golangci-cache /root/.cache/golangci-lint
+CACHE --sharing=shared --id go-build-cache /go/pkg/mod /root/.cache/go-build /root/.cache/golangci-lint

34-35: Set a specific timeout for golangci-lint

The current lint command uses a timeout of 5m. Depending on the project size, this might be insufficient or overly generous. Ensure the timeout aligns with expected linting durations.


39-41: Include generate step in pre-commit

To ensure that generated files are up-to-date before committing, consider adding the generate build step to the pre-commit target.

 pre-commit:
     BUILD +tidy
     BUILD +lint
+    BUILD +generate
deployments/pulumi/main_test.go (1)

88-89: Provide more context in error messages

The error messages in deployPostgres lack context. Enhance them to make debugging easier.

Apply this diff:

 if err != nil {
-    return fmt.Errorf("installing release")
+    return fmt.Errorf("installing PostgreSQL release: %w", err)
 }
Earthfile (1)

Line range hint 108-121: Consider using multi-stage builds for test dependencies

In the tests section, the image installs dependencies that may not be needed in the final image. Use multi-stage builds to keep the final image lean.

Refactor the tests section to separate dependency installation from test execution.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between b2b240e and 8298be8.

⛔ Files ignored due to path filters (2)
  • deployments/pulumi/go.mod is excluded by !**/*.mod
  • deployments/pulumi/go.sum is excluded by !**/*.sum, !**/*.sum
📒 Files selected for processing (8)
  • Earthfile (1 hunks)
  • deployments/pulumi/Earthfile (1 hunks)
  • deployments/pulumi/main.go (2 hunks)
  • deployments/pulumi/main_test.go (1 hunks)
  • deployments/pulumi/pkg/component.go (1 hunks)
  • test/rolling-upgrades/Earthfile (0 hunks)
  • test/rolling-upgrades/README.md (0 hunks)
  • test/rolling-upgrades/main_test.go (0 hunks)
💤 Files with no reviewable changes (3)
  • test/rolling-upgrades/Earthfile
  • test/rolling-upgrades/README.md
  • test/rolling-upgrades/main_test.go
🔇 Additional comments (2)
deployments/pulumi/main.go (1)

12-12: Update function call to use correct deployment function name

The function deploy is now being used instead of deployLedger. Ensure that this change is intentional and consistent throughout the codebase.

Earthfile (1)

147-147: Verify wildcard build paths in pre-commit

The line BUILD ./deployments/*+pre-commit uses a wildcard that may unintentionally include unwanted directories or files. Verify that it only targets the intended build scripts.

Run the following script to list the targeted build files:

✅ Verification successful

Wildcard build path in pre-commit is safe and targets only the intended file

The wildcard pattern ./deployments/*+pre-commit only matches one Earthfile located at ./deployments/pulumi/Earthfile, making it a safe and controlled build path.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# List all Earthfiles targeted by the wildcard
fd 'Earthfile' ./deployments/ --exec echo {}

Length of output: 77

@@ -3,17 +3,16 @@ package main
import (
"errors"
"fmt"
helm "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/helm/v3"
"github.com/formancehq/ledger/deployments/pulumi/pkg"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add alias for 'pulumi_ledger' in the import statement

The package github.com/formancehq/ledger/deployments/pulumi/pkg is used as pulumi_ledger in the code, but it is imported without an alias. To reference it correctly, you should add an alias in the import statement:

 import (
     "errors"
     "fmt"
+    pulumi_ledger "github.com/formancehq/ledger/deployments/pulumi/pkg"
     "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
     "github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
 )

Also applies to: 44-52

Comment on lines +62 to +65
debug := pulumix.Val(true)
if args.Debug != nil {
debug = args.Debug.ToOutput(ctx.Context())
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Set debug to false by default

Currently, debug defaults to true if not specified. For production environments, it may be safer to default this to false.

Apply this diff to change the default value:

-debug := pulumix.Val(true)
+debug := pulumix.Val(false)
 if args.Debug != nil {
     debug = args.Debug.ToOutput(ctx.Context())
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
debug := pulumix.Val(true)
if args.Debug != nil {
debug = args.Debug.ToOutput(ctx.Context())
}
debug := pulumix.Val(false)
if args.Debug != nil {
debug = args.Debug.ToOutput(ctx.Context())
}

Comment on lines 67 to 70
experimentalFeatures := pulumix.Val(true)
if args.ExperimentalFeatures != nil {
experimentalFeatures = args.ExperimentalFeatures.ToOutput(ctx.Context())
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Set experimentalFeatures to false by default

Similar to debug, experimentalFeatures defaults to true. It may be prudent to disable experimental features by default.

Apply this diff:

-experimentalFeatures := pulumix.Val(true)
+experimentalFeatures := pulumix.Val(false)
 if args.ExperimentalFeatures != nil {
     experimentalFeatures = args.ExperimentalFeatures.ToOutput(ctx.Context())
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
experimentalFeatures := pulumix.Val(true)
if args.ExperimentalFeatures != nil {
experimentalFeatures = args.ExperimentalFeatures.ToOutput(ctx.Context())
}
experimentalFeatures := pulumix.Val(false)
if args.ExperimentalFeatures != nil {
experimentalFeatures = args.ExperimentalFeatures.ToOutput(ctx.Context())
}

Comment on lines 175 to 180
Value: boolToString(pulumix.Apply2Err(autoUpgrade, waitUpgrade, func(autoUpgrade, waitUpgrade bool) (bool, error) {
if waitUpgrade && !autoUpgrade {
return false, fmt.Errorf("waitUpgrade requires autoUpgrade to be true")
}
return true, nil
})).Untyped().(pulumi.StringOutput),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure autoUpgrade and waitUpgrade logic is correct

The AUTO_UPGRADE environment variable is set to "true" regardless of the input values, due to the Apply2Err function always returning true if no error occurs. Review the logic to ensure it reflects the intended behavior.

Consider revising the logic:

corev1.EnvVarArgs{
    Name: pulumi.String("AUTO_UPGRADE"),
-   Value: boolToString(pulumix.Apply2Err(autoUpgrade, waitUpgrade, func(autoUpgrade, waitUpgrade bool) (bool, error) {
+   Value: boolToString(pulumix.Apply2Err(autoUpgrade, waitUpgrade, func(autoUpg, waitUpg bool) (bool, error) {
        if waitUpg && !autoUpg {
            return false, fmt.Errorf("waitUpgrade requires autoUpgrade to be true")
        }
-       return true, nil
+       return autoUpg, nil
    })).Untyped().(pulumi.StringOutput),
},
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Value: boolToString(pulumix.Apply2Err(autoUpgrade, waitUpgrade, func(autoUpgrade, waitUpgrade bool) (bool, error) {
if waitUpgrade && !autoUpgrade {
return false, fmt.Errorf("waitUpgrade requires autoUpgrade to be true")
}
return true, nil
})).Untyped().(pulumi.StringOutput),
Value: boolToString(pulumix.Apply2Err(autoUpgrade, waitUpgrade, func(autoUpg, waitUpg bool) (bool, error) {
if waitUpg && !autoUpg {
return false, fmt.Errorf("waitUpgrade requires autoUpgrade to be true")
}
return autoUpg, nil
})).Untyped().(pulumi.StringOutput),

ctx := logging.TestingContext()
stackName := "ledger-tests-pulumi-" + uuid.NewString()[:8]

stack, err := auto.UpsertStackInlineSource(ctx, stackName, "ledger-tests-pulumi-postgres", deployPostgres(stackName))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle potential errors from UpsertStackInlineSource

Check for errors returned by auto.UpsertStackInlineSource to ensure that stack creation or update issues are properly handled.

Apply this diff:

 stack, err := auto.UpsertStackInlineSource(ctx, stackName, "ledger-tests-pulumi-postgres", deployPostgres(stackName))
-if err != nil {
-    require.NoError(t, err)
-}
+require.NoError(t, err, "failed to upsert stack")

Committable suggestion skipped: line range outside the PR's diff.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (7)
deployments/pulumi/main.go (2)

Line range hint 15-43: Consider enhancing error handling for optional configurations

While the error handling for critical configurations like timeout is robust, consider logging when optional configurations (debug, imagePullPolicy, etc.) are missing to aid in troubleshooting.

-	debug, _ := conf.TryBool("debug")
-	imagePullPolicy, _ := conf.Try("image.pullPolicy")
+	debug, err := conf.TryBool("debug")
+	if err != nil && !errors.Is(err, config.ErrMissingVar) {
+		ctx.Log.Debug(fmt.Sprintf("debug config not provided: %v", err))
+	}
+	imagePullPolicy, err := conf.Try("image.pullPolicy")
+	if err != nil && !errors.Is(err, config.ErrMissingVar) {
+		ctx.Log.Debug(fmt.Sprintf("imagePullPolicy config not provided: %v", err))
+	}

44-54: Add documentation for component arguments

Consider adding comments to document the purpose and expected values for each component argument, especially for critical settings like Timeout and ExperimentalFeatures.

 	_, err = pulumi_ledger.NewComponent(ctx, "ledger", &pulumi_ledger.ComponentArgs{
+		// Namespace where the ledger will be deployed
 		Namespace:       pulumi.String(namespace),
+		// Timeout in seconds for deployment operations
 		Timeout:         pulumi.Int(timeout),
+		// Container image tag to deploy
 		Tag:             pulumi.String(version),
+		// Kubernetes image pull policy (e.g., Always, IfNotPresent)
 		ImagePullPolicy: pulumi.String(imagePullPolicy),
 		Postgres: pulumi_ledger.PostgresArgs{
+			// PostgreSQL connection URI
 			URI: pulumi.String(postgresURI),
 		},
+		// Enable debug mode for verbose logging
 		Debug:                pulumi.Bool(debug),
+		// Number of replicas to deploy
 		ReplicaCount:         pulumi.Int(replicaCount),
+		// Toggle experimental features (see documentation)
 		ExperimentalFeatures: pulumi.Bool(experimentalFeatures),
 	})
deployments/pulumi/pkg/component.go (5)

18-86: Add documentation for exported types and their fields.

The exported types would benefit from documentation comments explaining their purpose and the meaning of their fields, especially for configuration options that affect runtime behavior.


88-102: Enhance error handling in component initialization.

Consider wrapping the error from RegisterComponentResource with additional context using fmt.Errorf.

 err := ctx.RegisterComponentResource("Formance:Ledger", name, cmp, opts...)
 if err != nil {
-    return nil, err
+    return nil, fmt.Errorf("failed to register component resource: %w", err)
 }

508-539: Add backoff limit to migration job

Consider adding a backoff limit to prevent infinite retries if the migration consistently fails.

 Spec: batchv1.JobSpecArgs{
+    BackoffLimit: pulumi.Int(6),
     Template: corev1.PodTemplateSpecArgs{

542-558: Consider making service type configurable

The service type is hardcoded to ClusterIP. Consider adding a configuration option in ComponentArgs to allow different service types (e.g., NodePort, LoadBalancer) based on deployment requirements.


585-592: Improve error message for output registration

The error message could be more specific about which component failed.

 if err := ctx.RegisterResourceOutputs(cmp, pulumi.Map{
     "service-name":         cmp.ServiceName,
     "service-namespace":    cmp.ServiceNamespace,
     "service-port":         cmp.ServicePort,
     "service-internal-url": cmp.ServiceInternalURL,
 }); err != nil {
-    return nil, fmt.Errorf("registering resource outputs: %w", err)
+    return nil, fmt.Errorf("registering ledger component outputs: %w", err)
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8298be8 and 1ed7c23.

📒 Files selected for processing (2)
  • deployments/pulumi/main.go (2 hunks)
  • deployments/pulumi/pkg/component.go (1 hunks)
🔇 Additional comments (5)
deployments/pulumi/main.go (2)

6-6: Add alias for the ledger package import

The package is used as pulumi_ledger in the code but imported without an alias.


11-13: LGTM! Function rename reflects the broader scope

The rename from deployLedger to deploy aligns with the restructuring mentioned in the summary.

deployments/pulumi/pkg/component.go (3)

597-604: LGTM!

The helper function is well-implemented and serves its purpose effectively.


111-114: ⚠️ Potential issue

Set debug to false by default

Currently, debug defaults to true if not specified. For production environments, it may be safer to default this to false.

-debug := pulumix.Val(true)
+debug := pulumix.Val(false)
 if args.Debug != nil {
     debug = args.Debug.ToOutput(ctx.Context())
 }

132-140: ⚠️ Potential issue

Review default values for upgrade settings

Both autoUpgrade and waitUpgrade default to true, which could be risky in production. Consider defaulting these to false to require explicit opt-in for automatic upgrades.

-autoUpgrade := pulumix.Val(true)
+autoUpgrade := pulumix.Val(false)
 if args.AutoUpgrade != nil {
     autoUpgrade = args.AutoUpgrade.ToOutput(ctx.Context())
 }

-waitUpgrade := pulumix.Val(true)
+waitUpgrade := pulumix.Val(false)
 if args.WaitUpgrade != nil {
     waitUpgrade = args.WaitUpgrade.ToOutput(ctx.Context())
 }

Likely invalid or redundant comment.

},
Debug: pulumi.Bool(debug),
ReplicaCount: pulumi.Int(replicaCount),
ExperimentalFeatures: pulumi.Bool(experimentalFeatures),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Add documentation for experimental features flag

The experimentalFeatures flag is used across the codebase to enable feature configurability and is controlled via the --experimental-features CLI flag or EXPERIMENTAL_FEATURES environment variable. However, there is no clear documentation about what features are enabled/disabled by this flag.

  • Add documentation in README.md or a dedicated configuration guide explaining:
    • The purpose of the experimental features flag
    • List of features that are controlled by this flag
    • Implications of enabling/disabling these features
    • Default behavior when the flag is not set
🔗 Analysis chain

Verify documentation for experimental features

The experimentalFeatures flag has been added, but its implications and available features should be documented.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for documentation about experimental features
echo "Searching for experimental features documentation..."
rg -i "experimental.*features?" --type md

Length of output: 158


Script:

#!/bin/bash
# Let's try a broader search for experimental features in all file types
echo "Searching for experimental features in all files..."
rg -i "experimental.*features?" -A 3 -B 3

# Also search for any configuration or settings documentation
echo -e "\nSearching for config/settings documentation..."
fd -e md -e txt "config|settings|docs" --exec cat {}

Length of output: 10991

},
},
Spec: appsv1.DeploymentSpecArgs{
Replicas: pulumi.Int(1),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use configurable replica count

The replica count is hardcoded to 1, but args.ReplicaCount is defined in ComponentArgs. Use the provided configuration.

-Replicas: pulumi.Int(1),
+Replicas: args.ReplicaCount.ToOutput(ctx.Context()).Untyped().(pulumi.IntOutput),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Replicas: pulumi.Int(1),
Replicas: args.ReplicaCount.ToOutput(ctx.Context()).Untyped().(pulumi.IntOutput),

@gfyrag gfyrag force-pushed the refacto/rolling-upgrades-tests branch from 1ed7c23 to cd4625b Compare December 5, 2024 14:19
@gfyrag gfyrag force-pushed the refacto/rolling-upgrades-tests branch from cd4625b to bdf9a16 Compare December 5, 2024 14:24
@gfyrag gfyrag changed the title feat: some pulumi split chore: remove some infrastructure tests (moved to dedicated repository) Dec 5, 2024
@gfyrag gfyrag added this pull request to the merge queue Dec 5, 2024
Merged via the queue into main with commit b69289b Dec 5, 2024
8 checks passed
@gfyrag gfyrag deleted the refacto/rolling-upgrades-tests branch December 5, 2024 14:38
@coderabbitai coderabbitai bot mentioned this pull request Dec 6, 2024
@coderabbitai coderabbitai bot mentioned this pull request Dec 18, 2024
@coderabbitai coderabbitai bot mentioned this pull request Feb 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants